

#include <glew.h>
#include <wglew.h>
#include <freeglut.h> 
#include <iostream>
#include <memory.h>
#include <string>
#include <sstream>
#include <vector>

#include <World.h>
#include <Camera.h>
#include <Parser.h>

#include <SDL.h>


unsigned RANDOM_SEED = 2400050;
World* game = 0;
float gamefps = 0.016f;

bool KeyState[256];
bool KeyStateChange[256];


std::string appFPS = "0";
std::string title = "Stroids";

///////////////////////////////////////////////////////////////////////
//used to change the game's window size
class MainWindowInterface
{
public:
	MainWindowInterface()
	:gameWindow(800,600)
	{}
	void Set(unsigned w, unsigned h)
	{ gameWindow.Set(w,h); }
	Global::Window gameWindow;
};
MainWindowInterface windowInterface;
Global::Window* Global::GameWindow = &windowInterface.gameWindow; //declared in GameGlobals.h
//////////////////////////////////////////////////////////////////////

void Update();
void Draw();
void KeyboardDown(unsigned char key, int x, int y);
void KeyboardUp(unsigned char key, int x, int y);
void MouseFunc(int button, int state, int x, int y);
void MouseMotionFunc(int x, int y);
void ResizeWindow(int w, int h);
float calculateFPS();


int main(int argc, char* argv[])
{
	////////////////////////////////////////////////
	//get config file and setup window dimensions
	INIFile* config = new INIFile();
	if(!config->Load("./config.ini"))
	{
		std::cerr<<"Error loacating config.ini\n";
		delete config;
		return 0;
	}

	unsigned w = 800;
	unsigned h = 600;
	config->GetValue("ScreenWidth",w);
	config->GetValue("ScreenHeight",h);
	windowInterface.Set( w, h );
	///////////////////////////////////////////////

	
	SDL_Init( SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO ); 

	glutInit ( &argc, argv );
	
	glutInitDisplayMode ( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE );

	srand( RANDOM_SEED );	
	
	glutInitWindowSize ( Global::GameWindow->GetW(), Global::GameWindow->GetH() );

	glutCreateWindow ( title.c_str() );
	glutIgnoreKeyRepeat(1);
	
	glewInit();

	if( !GLEW_VERSION_2_0 )
	{
		std::cout << "ERROR! OpenGL 2.0 Not supported.\n";
		std::cout << "VENDOR:    " << glGetString(GL_VENDOR) << std::endl;
		std::cout << "VERSION:   " << glGetString(GL_VERSION) << std::endl;
		std::cout << "RENDERER:  " << glGetString(GL_RENDERER) << std::endl;
		std::cout << "GLEW 2.0:  " << (GLEW_VERSION_2_0!=0) << std::endl;
		delete config;
		return 0;
	}
	
	game = new World(config);
	game->Initialize();

	memset( KeyState, 0, 256 );
	memset( KeyStateChange, 0, 256 );



	glutDisplayFunc ( Draw );
	glutIdleFunc ( Update );
	glutKeyboardFunc( KeyboardDown );
	glutKeyboardUpFunc( KeyboardUp );
	glutMouseFunc( MouseFunc );
	glutMotionFunc( MouseMotionFunc );
	glutPassiveMotionFunc( MouseMotionFunc );
	glutReshapeFunc( ResizeWindow );


	glutMainLoop();

	SDL_Quit();
	return 0;
}


void Update()
{ 
	game->ProcessCommands();
	game->Cleanup();

	game->Input( KeyState, gamefps );
	game->Update( gamefps );

	//calculate and show fps
	std::stringstream toStr;
	toStr << calculateFPS();
	appFPS = toStr.str();
	glutSetWindowTitle( (title + " - " + appFPS).c_str() );

	//Update mouse buttons
	Button::buttontype& buttonFlags = Global::Mouse::ButtonStates;

	//See if left button is held
	if( buttonFlags & Button::LEFT_DOWN )
	{
		buttonFlags &= ~(Button::LEFT_DOWN);
		buttonFlags |= Button::LEFT_HELD;
	}
	else if( buttonFlags & Button::LEFT_UP )
	{
		buttonFlags &= ~(Button::LEFT_UP);
	}
	
	//See if right button is held
	if( buttonFlags & Button::RIGHT_DOWN )
	{
		buttonFlags &= ~(Button::RIGHT_DOWN);
		buttonFlags |= Button::RIGHT_HELD;
	}
	else if( buttonFlags & Button::RIGHT_UP )
	{
		buttonFlags &= ~(Button::RIGHT_UP);
	}
	
	//See clear down/up states for middle mouse
	if( buttonFlags & Button::MIDDLE_DOWN )
	{
		buttonFlags &= ~(Button::MIDDLE_DOWN);
	}
	else if( buttonFlags & Button::MIDDLE_UP )
	{
		buttonFlags &= ~(Button::MIDDLE_UP);
	}
}

void Draw()
{
	glClearColor(0.0,0.0,0.0,1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	game->Draw();
	glColor4f(1.0f,1.0f,1.0f,1.0f);

	glutSwapBuffers();
	glutPostRedisplay();
}

void KeyboardDown(unsigned char key, int x, int y)
{
	//std::cout<<key <<" was pressed!\n";

	KeyStateChange[key] = !KeyState[key];
	KeyState[key] = true;
}

void KeyboardUp(unsigned char key, int x, int y)
{
	KeyStateChange[key] = KeyState[key];
	KeyState[key] = false;
}


void MouseFunc(int button, int state, int x, int y)
{
	Button::buttontype& buttonFlags = Global::Mouse::ButtonStates;

	if( button == GLUT_LEFT_BUTTON )
	{
		if(state == GLUT_DOWN)
		{
			buttonFlags |= Button::LEFT_DOWN;
		}
		else if(state == GLUT_UP)
		{
			buttonFlags |= Button::LEFT_UP;
			buttonFlags &= ~(Button::LEFT_HELD);
		}
	}
	
	if( button == GLUT_MIDDLE_BUTTON )
	{
		if(state == GLUT_DOWN)
		{
			buttonFlags |= Button::MIDDLE_DOWN;
		}
		else if(state == GLUT_UP)
		{
			buttonFlags |= Button::MIDDLE_UP;
		}
	}
	
	if( button == GLUT_RIGHT_BUTTON )
	{
		if(state == GLUT_DOWN)
		{
			buttonFlags |= Button::RIGHT_DOWN;
		}
		else if(state == GLUT_UP)
		{
			buttonFlags |= Button::RIGHT_UP;
			buttonFlags &= ~(Button::RIGHT_HELD);
		}
	}
}

void MouseMotionFunc(int x, int y)
{
	Global::Mouse::ScreenPos = vec2(x,y);
}

void ResizeWindow(int w, int h)
{
	windowInterface.Set( w, h );
	game->GetCamera()->ResizeWindow( w, h );
}

//-------------------------------------------------------------------------
// Calculates the frames per second
//-------------------------------------------------------------------------
float calculateFPS()
{
	static int frameCount = 0;
	static int currentTime = 0;
	static int previousTime = 0;
	static float fps = 0;
    //  Increase frame count
    frameCount++;

    //  Get the number of milliseconds since last time calculation
    currentTime = SDL_GetTicks();

    //  Calculate time passed
    int timeInterval = currentTime - previousTime;

    if(timeInterval > 1000)
    {
        //  calculate the number of frames per second
        fps = frameCount / (timeInterval / 1000.0f);

		gamefps = (timeInterval / 1000.0f) / frameCount;

        //  Set time
        previousTime = currentTime;

        //  Reset frame count
        frameCount = 0;
    }

	return fps;
}